package test.service.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import test.service.Generator4MethodAccessor;
import test.service.MethodAccessor;
import test.utils.ClassUtility;
import test.utils.DynamicCompilerAndLoad;
import test.utils.IsGetterOrSetter;
import test.utils.StringUtility;

import java.lang.reflect.Method;

/**
 * Created with IntelliJ IDEA.
 *
 * @ project name : example
 * @ Author: XuLeHuang
 * @ Date: 2022/10/2 18:48
 * @ Description:
 */
@Component
public class Generator4MethodAccessorImpl implements Generator4MethodAccessor {
    private static Logger logger = LoggerFactory.getLogger(DynamicCompilerAndLoad.class);
    private static final String PACKAGE_NAME ="test.accessMethod";
    @Override
    public MethodAccessor newMethodAccessor(Class<?> clazz) {
        //反射获取类信息
        //1.简单类名
        String simpleName = clazz.getSimpleName();
        String clazzName = clazz.getName();
        String operatorObjectName = StringUtility.setFirstByteLowerCase(clazz
                .getSimpleName());
        //2.构造公共部分
        StringBuilder CommonToString = new StringBuilder("public class " + simpleName + " {");
        //3.get方法部分
        StringBuilder getMethodToString = new StringBuilder("public Object get(Object o, String methodName){");
        getMethodToString.append("\r\n");
        getMethodToString.append(String.format("%1$s %2$s = (%1$s) o;" , simpleName , operatorObjectName));
        //4.set方法部分
        StringBuilder setMethodToString = new StringBuilder("public void set(Object o, String methodName,Object arg){");
        setMethodToString.append("\r\n");
        setMethodToString.append(String.format("%1$s %2$s = (%1$s) o;" , simpleName , operatorObjectName));


        //5.获取一个实体的所有方法，遍历是否为get或者set方法
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            String methodName = declaredMethod.getName();
            Class<?>[] parameterTypes = declaredMethod.getParameterTypes();

            //get方法
            if (IsGetterOrSetter.isGetter(methodName)
                    && parameterTypes.length == 0
                && !declaredMethod.getReturnType().equals(void.class)) {
                getMethodToString.append("\r\n");
                getMethodToString.append(String.format("if (methodName.equalsIgnoreCase(\"%1$s\") || methodName.equalsIgnoreCase(\"%2$s\")) {"
                , methodName , methodName.substring(3)));
                getMethodToString.append("\r\n");
                getMethodToString.append(String.format("return %1$s.%2$s();}" , operatorObjectName , methodName));
                getMethodToString.append("\r\n");
            } else if (IsGetterOrSetter.isSetter(methodName)
                    &&  parameterTypes.length == 1
                    &&  declaredMethod.getReturnType().equals(void.class)) {
                setMethodToString.append("\r\n");
                setMethodToString.append(String.format("if (methodName.equalsIgnoreCase(\"%1$s\") || methodName.equalsIgnoreCase(\"%2$s\")) {"
                        , methodName.toLowerCase() , methodName.substring(3)));
                setMethodToString.append("\r\n");
                //todo
                setMethodToString.append(String.format("%1$s.%2$s((%3$s) arg);}" , operatorObjectName , methodName , ClassUtility.getWrapClass(parameterTypes[0])));
                setMethodToString.append("\r\n");
            }
        }

        //6.拼接尾部
        getMethodToString.append("return null;");
        getMethodToString.append("\r\n");
        getMethodToString.append("}");
        getMethodToString.append("\r\n");
        setMethodToString.append("}");
        setMethodToString.append("\r\n");

        //7.拼接源码
        String methodAccessorClassName = simpleName + "MethodAccess";

        //8.构建源码
        //todo
        String sourceCode = "package " + PACKAGE_NAME + ";" + "\r\n"
                + "import test.service.MethodAccessor;"
                + "\r\n" + "import " + clazzName + ";"
                + "\r\n" + " public class "
                + methodAccessorClassName + "  implements MethodAccessor{"
                + "\r\n" + getMethodToString.toString()
                + setMethodToString.toString() + "}";


        //动态加载器加载这个源码：编译+加载
        try {
            return (MethodAccessor) DynamicCompilerAndLoad
                    .getInstance().sourceToObject(
                            PACKAGE_NAME + "." + methodAccessorClassName,
                            sourceCode);
        } catch (Exception e) {
            logger.error("DynamicCompiler get sourceToObject error", e);
        }
        return null;
    }
}


